/**************************************************************************************************
* Title: SumDelegate.h
* Author: Gael Huber
* Description: Defines multiple wrappers for function pointers to be used as delegates. Provides
*	much easier usability especially for non-static member functions.
**************************************************************************************************/
#ifndef __SUMDELEGATE_H__
#define __SUMDELEGATE_H__

#include <assert.h>

// Namespace used to hide details of the system from the outside world. Can still be accessed, but
// it keeps the nasty stuff more tightly wrapped.

namespace bind_innards {

// Implicit class simply takes in the going class and reinterprets it as another class. Similar to
// static_cast.
template <class OutputClass, class InputClass>
inline OutputClass implicitCast(InputClass ic)
{
	return ic;
}

// Union of two general classes. This is primarily used for the class conversion system for proper
// method binding
template <class OutputClass, class InputClass>
union classUnion
{
	OutputClass output;
	InputClass input;
};

// Binding method that allows a generalized conversion from any given class to any other class. 
// This allows us to dynamically convert classes and deal with the data generically. Classes
// must be the same size in order for a union to work properly and the cast to work as it should.
// Otherwise, you are likely to encounter undefined behavior.
template <class OutputClass, class InputClass>
inline OutputClass convertClass(const InputClass ic)
{
	classUnion<OutputClass, InputClass> u;
	u.input = ic;
	return u.output;
}

// Define a generic class used for single inheritance. This forces the empty class to be
// represented by 4 bytes.
class __single_inheritance GenericClass;

// Constant used for the size of a single-inheritance class member function pointer
const int SINGLE_INHERITANCE_MEMFUNC_SIZE = sizeof(void (GenericClass::*)());

// General case conversion for the case below. Unsure of conversion method for this general method,
// so force failure.
template <int N>
struct SimplifyMemberFunction {
	template <class X, class XFunctionType, class GenericMemberFunctionType>
	inline static GenericClass* convert(X* pThis, XFunctionType functionToBind,
		GenericMemberFunctionType& boundFunction)
	{
		return 0;
	}
};

// Convert an arbitrary member function pointer into the simplest form of member function pointer.
// Only single inheritance classes are permitted to go here as function pointer sizes may vary for
// multiple inheritance classes, therefore they do not work in the same way.
template <>
struct SimplifyMemberFunction<SINGLE_INHERITANCE_MEMFUNC_SIZE> {
	template <class X, class XFunctionType, class GenericMemberFunctionType>
	inline static GenericClass* convert(X* pThis, XFunctionType functionToBind, 
		GenericMemberFunctionType& boundFunction)
	{
		boundFunction = reinterpret_cast<GenericMemberFunctionType>(functionToBind);
		return reinterpret_cast<GenericClass*>(pThis);
	}
};

// Convert an arbitrary member function pointer into the simplest form of member function pointer.
// Multiple inheritance classes go here as reinterpret_cast must account for the difference in size
// from a single-inheritance function pointer.
template <>
struct SimplifyMemberFunction<SINGLE_INHERITANCE_MEMFUNC_SIZE + sizeof(int)> {
	template <class X, class XFunctionType, class GenericMemberFunctionType>
	inline static GenericClass* convert(X* pThis, XFunctionType functionToBind,
		GenericMemberFunctionType& boundFunction)
	{
		union {
			XFunctionType function;
			struct {
				GenericMemberFunctionType functionAddress;	// Points to the address of the member function
				int extraBytes;		// Number of bytes to be added to 'this' pointer
			} s;
		} u;

		// Attach the function to bind
		u.function = functionToBind;
		boundFunction = u.s.functionAddress;

		// Return the same value as with single-inheritance classes with the exception that
		// multiple-inheritance classes will add an extra amount to the pointer to notate
		// the extra size of the pointer.
		return reinterpret_cast<GenericClass*>(reinterpret_cast<char*>(pThis) + u.s.extraBytes);
	}
};

} // End bind_innards

template<class ReturnType=void>
class Delegate {
public:
	inline Delegate()
		: pThis(0)
	{ }

protected:
	bind_innards::GenericClass* pThis;	// Our generic pointer to a 'this' object
};

// The actual delegate class for a no-parameter function. This will take care of pairing the
// function to the delegate object. The default return type is void.
template<class ReturnType=void>
class Delegate0 {
public:
	// Constructor that does not bind by default
	inline Delegate0(void)
		: pThis(0), memberFunction(0)
	{ }

	// Constructor that binds by default
	template <class X, class Y>
	inline Delegate0(Y* tpThis, ReturnType (X::*functionToBind)())
	{
		bindMemberFunction(bind_innards::implicitCast<X*>(tpThis), functionToBind);
	}

	// Call the function bind
	template <class X, class Y>
	inline void bind(Y* tpThis, ReturnType (X::*functionToBind)())
	{
		bindMemberFunction(bind_innards::implicitCast<X*>(tpThis), functionToBind);
	}

	// Invoke the function
	inline ReturnType operator() (void) const
	{
		return (pThis->*memberFunction)();
	}

private:
	// Performs the actual function bind
	template <class X, class XMemberFunction>
	inline void bindMemberFunction(X* tpThis, XMemberFunction functionToBind)
	{
		pThis = bind_innards::SimplifyMemberFunction<sizeof(functionToBind)>::convert(tpThis, functionToBind, memberFunction);
	}

private:
	typedef ReturnType (bind_innards::GenericClass::*GenericMemberFunctionType)(); // Arbitrary function 
		// pointer used to permit usage of GenericMemberFunctionPointer below.
	bind_innards::GenericClass* pThis;	// Our generic pointer to a 'this' object
	GenericMemberFunctionType memberFunction;	// Function pointer
};

// The actual delegate class for a no-parameter function. This will take care of pairing the
// function to the delegate object. The default return type is void.
template<class P1, class ReturnType=void>
class Delegate1 : public Delegate<ReturnType> {
public:
	// Constructor that does not bind by default
	inline Delegate1(void)
		: pThis(0), memberFunction(0)
	{ }

	// Constructor that binds by default
	template <class X, class Y>
	inline Delegate1(Y* tpThis, ReturnType (X::*functionToBind)(P1 p1))
	{
		bindMemberFunction(bind_innards::implicitCast<X*>(tpThis), functionToBind);
	}

	// Call the function bind
	template <class X, class Y>
	inline void bind(Y* tpThis, ReturnType (X::*functionToBind)(P1 p1))
	{
		bindMemberFunction(bind_innards::implicitCast<X*>(tpThis), functionToBind);
	}

	// Invoke the function
	inline ReturnType operator() (P1 p1) const
	{
		return (pThis->*memberFunction)(p1);
	}

private:
	// Performs the actual function bind
	template <class X, class XMemberFunction>
	inline void bindMemberFunction(X* tpThis, XMemberFunction functionToBind)
	{
		pThis = bind_innards::SimplifyMemberFunction<sizeof(functionToBind)>::convert(tpThis, functionToBind, memberFunction);
	}

private:
	typedef ReturnType (bind_innards::GenericClass::*GenericMemberFunctionType)(P1); // Arbitrary function 
		// pointer used to permit usage of GenericMemberFunctionPointer below.
	GenericMemberFunctionType memberFunction;	// Function pointer
};

#endif